package com.dbb.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.Table;

import org.apache.commons.beanutils.MethodUtils;
import org.springframework.beans.BeanUtils;

import com.goldstone.entity.Version;

public class BeanUtil<T> extends BeanUtils { 
	List<Version> compare(T o, T n) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
		List<Version> versions = new ArrayList<Version>();
		if(isEntity(o.getClass()) && isEntity(n.getClass())) {
			List<String> methodNames = getMethods(o);
			Object oldValue;
			Object newValue;
			for(String methodName : methodNames) {
				oldValue = MethodUtils.invokeMethod(o, methodName, null);
				newValue = MethodUtils.invokeMethod(n, methodName, null);
				if((oldValue!=null&&isSimpleProperty(oldValue.getClass()))||(newValue!=null&&isSimpleProperty(newValue.getClass()))) {
					if(!oldValue.equals(newValue)) {
						Version version = new Version(getTableName(o.getClass()), getString(MethodUtils.invokeMethod(o, "getId", null)));
						version.setVersionNum(getString(MethodUtils.invokeMethod(o, "getVersion", null)));
						version.setProp(methodName);
						version.setPropType(o.getClass().getMethod(methodName).getReturnType().getName());
						version.setFromValue(getString(oldValue));
						version.setToValue(getString(newValue));
						versions.add(version);
					}
				}
			}
		}
		
		return versions;
	}
	
	public boolean isEntity(Class c) {
		return c.isAnnotationPresent(Entity.class);
	}
	
	public String getTableName(Class c) {
		if(isEntity(c)) {
			if(c.isAnnotationPresent(Table.class)) {
				return ((Table) c.getAnnotation(Table.class)).name();
			} else {
				return StringUtils.getTableName(c);
			}
		} else {
			return "";
		}
	}
	
	public List<String> getMethods(T t) {
		Method[] methods = t.getClass().getMethods();
		List<String> methodNames = new ArrayList<String>();
		for(Method method : methods) {
			if(method.getName().startsWith("get") && !"getClass".equals(method.getName())  && !"getVersion".equals(method.getName()) && !"getId".equals(method.getName())){
				methodNames.add(method.getName());
			}
		}
		return methodNames;
	}
	
	private String getString(Object o) {
		if(o == null) {
			return "";
		} else {
			return o.toString();
		}
	}
	
	void o(Object o) {
		System.out.println(o);
	}
}
